package com.luych.toolbox.common.xml;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.Map;

public class XmlNode2Xml {

    private final XmlNode node;

    public XmlNode2Xml(XmlNode node) {
        this.node = node;
    }

    private void convert(Document document, Element element, XmlNode node) {
        for (Map.Entry<String, String> entry : node.getAttrs().entrySet()) {
            element.setAttribute(entry.getKey(), entry.getValue());
        }
        if (node.getChildren().size() > 0) {
            for (XmlNode childNode : node.getChildren()) {
                Element childElement = document.createElement(childNode.getName());
                this.convert(document, childElement, childNode);
                element.appendChild(childElement);
            }
        } else if (node.getValue() != null) {
            element.setTextContent(node.getValue());
        }
    }

    public String convert() {
        try {
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            documentBuilderFactory.setExpandEntityReferences(false);
            documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
            DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder();
            Document document = builder.newDocument();
            Element root = document.createElement(node.getName());
            this.convert(document, root, node);
            document.appendChild(root);
            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer();
            DOMSource domSource = new DOMSource(document);
            StringWriter writer = new StringWriter();
            StreamResult result = new StreamResult(writer);
            transformer.setOutputProperty(OutputKeys.ENCODING, StandardCharsets.UTF_8.displayName());
            transformer.transform(domSource, result);
            return writer.getBuffer().toString();
        } catch (ParserConfigurationException | TransformerException e) {
            throw new RuntimeException(e);
        }
    }
}
